package com.cyy.util

import java.awt.BasicStroke
import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.util.HashMap

import javax.imageio.ImageIO

import com.google.zxing.BarcodeFormat
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.EncodeHintType
import com.google.zxing.MultiFormatReader
import com.google.zxing.MultiFormatWriter
import com.google.zxing.WriterException
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
import com.google.zxing.client.j2se.MatrixToImageConfig
import com.google.zxing.client.j2se.MatrixToImageWriter
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel

import javafx.embed.swing.SwingFXUtils
import javafx.scene.image.Image
import javafx.scene.paint.Color

/**
 * @ClassName: QRCodeUtil
 * @Description: 二维码工具类
 * @author: Administrator
 * @date: 2017年8月12日 下午2:21:08
 */
object QRCodeUtil {
    private val width = 300// 默认二维码宽度
    private val height = 300// 默认二维码高度
    private val format = "png"// 默认二维码文件格式
    private val hints = HashMap<EncodeHintType, Any>()// 二维码参数
    private val dhints = HashMap<DecodeHintType, Any>()// 识别二维码参数

    init {
        hints[EncodeHintType.CHARACTER_SET] = "utf-8"// 字符编码
        hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H// 容错等级 L、M、Q、H 其中 L 为最低, H 为最高
        hints[EncodeHintType.MARGIN] = 2// 二维码边界空白大小 1,2,3,4 (4为默认,最大)

        dhints[DecodeHintType.CHARACTER_SET] = "UTF-8"
    }

    /**
     * 返回一个 BufferedImage 对象
     *
     * @param content
     * 二维码内容
     * @param width
     * 宽
     * @param height
     * 高
     */
    @Throws(WriterException::class, IOException::class)
    @JvmOverloads
    fun toBufferedImage(content: String, width: Int, height: Int): BufferedImage {
        val bitMatrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
        return MatrixToImageWriter.toBufferedImage(bitMatrix)
    }

    /**
     * @Title: toImage
     * @Description: 转换为javaFxImage二维码图片
     */
    fun toImage(content: String, width: Int, height: Int): Image {
        val stream = ByteArrayOutputStream()
        try {
            writeToStream(content, stream, width, height)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return Image(ByteArrayInputStream(stream.toByteArray()))
    }

    fun toImage(content: String, width: Int, height: Int, format: String, errorCorrectionLevel: ErrorCorrectionLevel, margin: Int, onColor: Color, offColor: Color, formatImage: String): Image {
        val hints = HashMap<EncodeHintType, Any>()// 二维码参数
        hints[EncodeHintType.CHARACTER_SET] = format// 字符编码
        hints[EncodeHintType.ERROR_CORRECTION] = errorCorrectionLevel// 容错等级 L、M、Q、H 其中 L 为最低, H 为最高
        hints[EncodeHintType.MARGIN] = margin// 二维码边界空白大小 1,2,3,4 (4为默认,最大)
        val stream = ByteArrayOutputStream()
        try {
            val onColorw = java.awt.Color(onColor.red.toFloat(), onColor.green.toFloat(), onColor.blue.toFloat(), onColor.opacity.toFloat())
            val offColorw = java.awt.Color(offColor.red.toFloat(), offColor.green.toFloat(), offColor.blue.toFloat(), offColor.opacity.toFloat())
            val bitMatrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
            val config = MatrixToImageConfig(onColorw.rgb, offColorw.rgb)
            MatrixToImageWriter.writeToStream(bitMatrix, formatImage, stream, config)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return Image(ByteArrayInputStream(stream.toByteArray()))
    }

    /**
     * 二维码绘制logo
     * @param image 二维码图片文件
     * @param logoImg logo图片文件
     */
    fun encodeImgLogo(image: Image, logoImg: Image, logoSize: Int): Image {
        val twodimensioncode = SwingFXUtils.fromFXImage(image, null)
        try {
            //读取二维码图片
            //获取画笔
            val g = twodimensioncode.createGraphics()
            //读取logo图片
            val logo = SwingFXUtils.fromFXImage(logoImg, null)
            //设置二维码大小，太大，会覆盖二维码，此处15%
            val logoWidth = if (logo.getWidth(null) > twodimensioncode.width * logoSize / 100) twodimensioncode.width * logoSize / 100 else logo.getWidth(null)
            val logoHeight = if (logo.getHeight(null) > twodimensioncode.height * logoSize / 100) twodimensioncode.height * logoSize / 100 else logo.getHeight(null)
            //设置logo图片放置位置
            //中心
            val x = (twodimensioncode.width - logoWidth) / 2
            val y = (twodimensioncode.height - logoHeight) / 2
            //右下角，15为调整值
            //			int x = twodimensioncode.getWidth()  - logoWidth-15;
            //			int y = twodimensioncode.getHeight() - logoHeight-15;
            //开始合并绘制图片
            g.drawImage(logo, x, y, logoWidth, logoHeight, null)
            g.drawRoundRect(x, y, logoWidth, logoHeight, 15, 15)
            //logo边框大小
            g.stroke = BasicStroke(2f)
            //logo边框颜色
            g.color = java.awt.Color.WHITE
            g.drawRect(x, y, logoWidth, logoHeight)
            g.dispose()
            logo.flush()
            twodimensioncode.flush()
        } catch (e: Exception) {
            println("二维码绘制logo失败")
        }

        return SwingFXUtils.toFXImage(twodimensioncode, null)
    }

    fun encodeImgLogo(twodimensioncodeImg: File, logoImg: File): BufferedImage? {
        var twodimensioncode: BufferedImage? = null
        try {
            if (!twodimensioncodeImg.isFile || !logoImg.isFile) {
                println("输入非图片")
                return null
            }
            //读取二维码图片
            twodimensioncode = ImageIO.read(twodimensioncodeImg)
            //获取画笔
            val g = twodimensioncode!!.createGraphics()
            //读取logo图片
            val logo = ImageIO.read(logoImg)
            //设置二维码大小，太大，会覆盖二维码，此处20%
            val logoWidth = if (logo.getWidth(null) > twodimensioncode.width * 2 / 10) twodimensioncode.width * 2 / 10 else logo.getWidth(null)
            val logoHeight = if (logo.getHeight(null) > twodimensioncode.height * 2 / 10) twodimensioncode.height * 2 / 10 else logo.getHeight(null)
            //设置logo图片放置位置
            //中心
            val x = (twodimensioncode.width - logoWidth) / 2
            val y = (twodimensioncode.height - logoHeight) / 2
            //右下角，15为调整值
            //			int x = twodimensioncode.getWidth()  - logoWidth-15;
            //			int y = twodimensioncode.getHeight() - logoHeight-15;
            //开始合并绘制图片
            g.drawImage(logo, x, y, logoWidth, logoHeight, null)
            g.drawRoundRect(x, y, logoWidth, logoHeight, 15, 15)
            //logo边框大小
            g.stroke = BasicStroke(2f)
            //logo边框颜色
            g.color = java.awt.Color.WHITE
            g.drawRect(x, y, logoWidth, logoHeight)
            g.dispose()
            logo.flush()
            twodimensioncode.flush()
        } catch (e: Exception) {
            println("二维码绘制logo失败")
        }

        return twodimensioncode
    }

    /**
     * 从Image中解析二维码
     */
    fun toDecode(image: Image): String? {
        val bimage = SwingFXUtils.fromFXImage(image, null)
        return toDecode(bimage)
    }

    /**
     * 从BufferedImage中解析二维码
     */
    fun toDecode(bimage: BufferedImage): String? {
        try {
            val source = BufferedImageLuminanceSource(bimage)
            val binarizer = HybridBinarizer(source)
            val binaryBitmap = BinaryBitmap(binarizer)
            val result = MultiFormatReader().decode(binaryBitmap, dhints)// 对图像进行解码
            return result.text
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return null
    }

    /**
     * @Title: toDecode
     * @Description: 从文件总解析二维码
     */
    fun toDecode(file: File): String? {
        try {
            val image = ImageIO.read(file)
            val source = BufferedImageLuminanceSource(image)
            val binarizer = HybridBinarizer(source)
            val binaryBitmap = BinaryBitmap(binarizer)
            val result = MultiFormatReader().decode(binaryBitmap, dhints)// 对图像进行解码
            return result.text
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return null
    }

    /**
     * 将二维码图片输出到一个流中
     *
     * @param content
     * 二维码内容
     * @param stream
     * 输出流
     * @param width
     * 宽
     * @param height
     * 高
     */
    @Throws(WriterException::class, IOException::class)
    fun writeToStream(content: String, stream: OutputStream, width: Int, height: Int) {
        val bitMatrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
        //		MatrixToImageConfig config = new MatrixToImageConfig(java.awt.Color.GREEN.getRGB(), java.awt.Color.RED.getRGB());
        //		MatrixToImageWriter.writeToStream(bitMatrix, format, stream,config);
        MatrixToImageWriter.writeToStream(bitMatrix, format, stream)
    }

    /**
     * 生成二维码图片文件
     *
     * @param content
     * 二维码内容
     * @param path
     * 文件保存路径
     * @param width
     * 宽
     * @param height
     * 高
     */
    @Throws(WriterException::class, IOException::class)
    fun createQRCode(content: String, path: String, width: Int, height: Int) {
        val bitMatrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
        // toPath() 方法由 jdk1.7 及以上提供
        MatrixToImageWriter.writeToPath(bitMatrix, format, File(path).toPath())
    }
}
